package com.gopay.checkorder.service.task;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BisBankOrderQueryDAO;
import com.gopay.checkorder.service.BankOrderService;
import com.gopay.checkorder.service.alarm.OrderAlarmDataCollector;
import com.gopay.checkorder.service.alarm.OrderAlarmRecordStorage;
import com.gopay.checkorder.service.task.thread.CheckOrderTaskThread;
import com.gopay.checkorder.service.task.thread.CheckOrderThread;
import com.gopay.common.domain.bank.BankOrder;

/** 
 * 招行小时对账
 * @Description: TODO(这里用一句话描述这个类的作用) 
 * @author w_jiqing 
 * @date 2016年10月31日 下午5:14:28  
 */ 
public class CmbCheckOrderPerHourTaskImpl implements Task{
    private final static Logger logger = LoggerFactory.getLogger("CHECK_ORDER");

    private final static int MAX_SIZE = 10000;

    @Resource(name = "bisBankOrderQueryDAO")
    private BisBankOrderQueryDAO bisBankOrderQueryDAO;

    @Resource(name = "checkOrderTaskThread")
    private CheckOrderTaskThread checkOrderTaskThread;
    
    @Resource(name = "bankOrderService")
    private BankOrderService bankOrderService;
    
    @Resource(name = "orderAlarmRecordStorage")
    private OrderAlarmRecordStorage orderAlarmRecordStorage;
    
    private String bank;
    
    private final static int THREAD_SIZE = 10;
    private ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_SIZE);

    private void printLog(StopWatch sw,String bank,String prefix){
        sw.split();
        logger.error(prefix+"------,bank="+bank+",耗时="+sw.getSplitTime());
    }

    /**
     * 任务执行
     */
    public void doTask() {
        try{
            StopWatch sw=new StopWatch();
            sw.start();
            printLog(sw,bank,"CheckOrderPerHourTaskImpl------start");
            
            int pageSize = 100;
            int pageIndex = 1;
            int count = 0;
    
            checkBefore();
            Date date = new Date();
            int resCount = getCheckOrderCount(date);
            printLog(sw,bank,"CheckOrderPerHourTaskImpl------对单总数量="+resCount);
            
            //订单对账报警采集者
            OrderAlarmDataCollector alarmCollector=new OrderAlarmDataCollector();
            
            List<BankOrder> list = null;
            while (count < resCount) {
                list = getCheckOrder(date, pageIndex, pageSize);
                if (list == null || list.size() == 0) {
                    printLog(sw,bank,"CheckOrderPerHourTaskImpl------分页为空，跳出while循环");
                    break;
                }
                printLog(sw,bank,"CheckOrderPerHourTaskImpl------list.size()="+list.size()+",pageIndex="+pageIndex);
    

                //订单队列              
                ConcurrentLinkedQueue<BankOrder> queue=new ConcurrentLinkedQueue<BankOrder>();
                queue.addAll(list);
    
                //同步锁存器
                CountDownLatch latch = new CountDownLatch(queue.size());
                
                //线程池中线程全部参与
                for(int i=0;i<THREAD_SIZE;i++){
                    CheckOrderThread thread=new CheckOrderThread(bankOrderService,queue,latch,alarmCollector);
                    threadPool.execute(thread);
                     
                }
                
                // 同步锁存器等待所有线程执行完成
                if(!latch.await(118, TimeUnit.SECONDS)){
                    logger.error("同步锁存器等待超时了 latch.count=" + latch.getCount());
                    threadPool.awaitTermination(1, TimeUnit.SECONDS);
                }

    
                count += pageSize;
                pageIndex++;
    
            }
            
            printLog(sw,bank,"CheckOrderPerHourTaskImpl------结束while循环,resCount="+resCount);
            
            //判断报警阈值并保存报警记录
            orderAlarmRecordStorage.store(alarmCollector);
            
            printLog(sw,bank,"CheckOrderPerHourTaskImpl------end");
            sw.stop();
            
        }catch (Throwable t) {
            logger.error("执行对单Task时出现异常" ,t);
        }      
    }
    
    /**
     * 
     */
    private void checkBefore() {
    }

    /**
     * 待对账订单笔数
     * @param orderStatus
     * @param totalCheckTimes
     * @return
     */
    protected int getCheckOrderCount(Date date){
        int resCount =0;
        if(StringUtils.isNotBlank(bank)){
            resCount=bisBankOrderQueryDAO.getCheckOrderCountByBankExcludeB2b(date, bank);
        }else{
            resCount=bisBankOrderQueryDAO.getCheckOrderCount(date);
        }
        
        if (resCount > MAX_SIZE) {
            resCount = MAX_SIZE;
        }
        return resCount;
    }
    
    /**
     * 分页查询对账记录
     * @param orderStatus
     * @param totalCheckTimes
     * @param pageIndex
     * @param pageSize
     * @return
     */
    protected List<BankOrder> getCheckOrder(Date date, int pageIndex, int pageSize){
        if(StringUtils.isNotBlank(bank)){
            return bisBankOrderQueryDAO.getCheckOrderByBankExcludeB2b(date, pageIndex, pageSize, bank);
        }else{
            return bisBankOrderQueryDAO.getCheckOrder(date, pageIndex, pageSize);
        }
    }
    
    public void setBank(String bank) {
        this.bank = bank;
    }
}
